Dynamic Arrays in Delphi
========================

This archive should contain the following files:

readme.txt    This file
arrays.hlp    Help file describing the array classes
arrays.pas    Unit implementing the array classes
fastmem.pas   Auxillary Unit used by Arrays.PAS, see helpfile
multidim.pas  Bonus Unit with a bare-bones multidimensional 
              array class.
arrtest.dpr   Project file for the test program
arrtest1.dfm  Main form of the test program
arrtest2.dfm  Secondary form
arrtest3.dfm  "
arrtest4.dfm  "
arrtest5.dfm  "
arrtest6.dfm  "
arrtest7.dfm  "
arrtest8.dfm  "
arrtest1.pas  Main Unit of the the test program
arrtest2.pas  Secondary unit
arrtest3.pas  "
arrtest4.pas  "
arrtest5.pas  "
arrtest6.pas  "
arrtest7.pas  "
arrtest8.pas  "

Author
======

Dr. Peter Below
e-mail: CIS 100113,1101
        Internet: 100113.1101@compuserve.com    (preferred)
                  below@msmrd.frankfurt.hoechst-ag.d400.de

This code is freeware and released to the public domain. You may use
it as you see fit in your own applications and distribute it as part
of an application without royalties. You may also distribute the
source code in this archive, preferrable in form of this archive,
provided that you give due credit to the author, include this section
of the readme file unchanged, and don't charge more for it than is
warranted by the cost of media and distribution per se.

I give no warranties as to the proper functioning of the code in this
archive. It has been tested under both Delphi 1.0 and Delphi 2.0 and
i'm not aware of any problems with it. However, that does not
guarantee that none exist, and i will not take responsibilty or
provide compensation for any damage done to software, data, hardware,
personal, lifestock, buildings, and the rest of the pyhsical and
spiritual world as a consequence of errors in this code!

Installation
============

The only files you need for using the array classes are arrays.pas
and fastmem.pas, copy these to a directory on your harddisk that is
on the LIB search path you have set in Delphi. You will probably also
want to use the help file, so copy arrays.hlp to a directory of your
choice and create a icon for it in your favourite program manager
group. There's no provision to integrate this helpfile into the
Delphi help system, sorry, you have to open and search it manually
(or use a proper editor like CodeWright, that can extract the
keywords from the helpfile itself <g>).

If you want to try the test program, copy the arrtest*.* files to a
directory on the harddisk, open the arrtest.dpr project and compile
it. The forms have been developed on 1024*768 large font video, i
hope they scale correctly on other resolutions. The test program just
shows how to use several of the array classes and features like
resize, sort and clone. It has no associated documentation, just play
around with it.

Description
===========

Arrays as implemented in Borland's Pascal dialect (and the Pascal
standard as defined by Wirth) are declared at compile time. If you
need to allocate an array with a size only known at run time the only
option is to use a pointer to a large array type and only allocate as
much memory as needed:

 Type
   TDoubleArray = Array [0..High(Word) div Sizeof(Double) - 1] of Double;
   PDoubleArray = ^TDoubleArray;
 
 Var
   pMyArray : PDoubleArray;
   i, numItems : Integer;
 Begin
   numItems := 200;
   GetMem( pMyArray, numItems * Sizeof(Double));
   For i:= 0 To Pred(numItems) Do
     pMyArray^[i] := ....

Such a dynamically allocated array can also be resized with
ReAllocMem. The main problem is keeping track of the actual upper
bound of the array. This approach effectively disables range checking
by the compiler since the type declaration for the array is what the
compiler uses to determine the highest valid index in its range
checking code. So you have to pass the actual size around with the
pointer to the array wherever you use it and guard against range
errors yourself. Combined with the issue of allocating and
deallocating memory correctly and the use of pointers (deemed
un-Pascalian by many) this is a source of errors that is hard to
avoid. Writing reusable code with such a construct is not impossible
but harder than it ought to be <g>.

The natural approach with OOP available in Delphi is to encapsulate
all this mess into a class and be done with it once and for all. This
is what the ARRAYS.PAS unit in this archive does. 

Many of the tasks such an array class has to do are actually
independent of the items it stores. These functionalities are thus
implemented in a base class, TBaseArray. This class has methods to
deal with data items on a rather abstract level. The only things it
needs to know are the size of a data item and how many it has to
store. That is enough to handle allocation and deallcoation of
memory, to provide basic support for sorting, insertion, deletion,
copying, to store and retrieve individual items. The class takes care
of all memory management related items, keeps count of how many items
it can store, does index range checking (if required), can be
resized, cloned, assigned, stored to stream or disk and read from the
same sources. Access to individual items requires method calls,
however, the common array syntax cannot be used here.

Specialized arrays for certain data types are derived from
TBaseArray. The Arrays Unit already provides a couple of these types
for the standard data types. These derived classes mainly do two
things: provide the correct sort method for this data type and
provide a Data property which allows access to items using the normal
array syntax.

There is a price for all this comfort: speed. Using objects entails a
certain overhead. To access a method or field of an object the
code has to load the address of the object first (indirect
referencing). Accessing an array item via the Data property also
involves a method call. The code has to execute more instructions to
access an item in an array object than to access one in a normal
array. This becomes rather noticeable in code that accesses all items
of an array in sequence, e.g. a loop over all array items to do a
sum. These can take 2-3 times as long with an array object. Using
one of the iterator methods for such a task adds another method call
and thus is even slower than a straight For loop using the Data
property!

In cases where speed is important it may pay to store the
Memory-property to a pointer-to-an-array-type variable and then
proceed as in the classical approach cited above.

The array classes are limited to 64KBytes in Delphi 1.0 since they
store all items in one contiguous memory block. This limit does not
exist in Delphi 2.0. The array classes are also one-dimensional only.
The sample class in MULTIDIM.PAS shows a possible approach to
building multidimensional array classes on top of the one-dimensional
ones in arrays.pas.

Have fun with these units and don't hesitate to contact me if you
have problems or questions.

May 1996
Peter Below
